package top.stmo.spring.ioc.test1;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import top.stmo.spring.ioc.test1.dao.BookDao;
import top.stmo.spring.ioc.test1.service.BookService;
import top.stmo.spring.ioc.test1.service.impl.BookServiceImpl;

import javax.sql.DataSource;

/**
 *    -------------------------依赖注入--------------------------
 *
 *    向一个类中传递数据的方式有几种?
 *      普通方法(set方法)
 *      构造方法
 *    依赖注入描述了在容器中建立bean与bean之间的依赖关系的过程，如果bean运行需要的是数字或
 *          字符串呢?
 *          引用类型
 *          简单类型(基本数据类型与String)
 *    Spring就是基于上面这些知识点，为我们提供了两种注入方式，分别是:
 *      setter注入
 *          简单类型
 *          引用类型
 *      构造器注入
 *          简单类型
 *          引用类型
 *
 *      两种参数的注入方式的选择
 *       1. 强制依赖使用构造器进行，使用setter注入有概率不进行注入导致null对象出现
 *       强制依赖指对象在创建的过程中必须要注入指定的参数
 *       2. 可选依赖使用setter注入进行，灵活性强,可选依赖指对象在创建过程中注入的参数可有可无
 *       3. Spring框架倡导使用构造器，第三方框架内部大多数采用构造器注入的形式进行数据初始化，相对严谨
 *       4. 如果有必要可以两者同时使用，使用构造器注入完成强制依赖的注入，使用setter注入完成可选依赖的注入
 *       5. 实际开发过程中还要根据实际情况分析，如果受控对象没有提供setter方法就必须使用构造器注入
 *       6. 自己开发的模块推荐使用setter注入
 *
 *    -------------------------依赖自动装配--------------------------
 *
 *    IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
 *
 *    自动装配方式有哪些?
 *      按类型（常用）
 *      按名称
 *      按构造方法
 *      不启用自动装配
 *
 *    1. 自动装配用于引用类型依赖注入，不能对简单类型进行操作
 *    2. 使用按类型装配时（byType）必须保障容器中相同类型的bean唯一，推荐使用
 *    3. 使用按名称装配时（byName）必须保障容器中具有指定名称的bean，因变量名与配置耦合，不推荐使用
 *    4. 自动装配优先级低于setter注入与构造器注入，同时出现时自动装配配置失效
 *
 *    -------------------------容器--------------------------
 *
 *    容器创建的两种方式
 *      ClassPathXmlApplicationContext[掌握]
 *      FileSystemXmlApplicationContext[知道即可]
 *    获取Bean的三种方式
 *      getBean("名称"):需要类型转换
 *      getBean("名称",类型.class):多了一个参数
 *      getBean(类型.class):容器中不能有多个该类的bean对象
 *    上述三种方式，各有各的优缺点，用哪个都可以。
 *      容器类层次结构
 *      只需要知晓容器的最上级的父接口为 BeanFactory即可
 *    BeanFactory
 *      使用BeanFactory创建的容器是延迟加载
 *      使用ApplicationContext创建的容器是立即加载
 *      具体BeanFactory如何创建只需要了解即可。
 *
 */
public class AppTest2 {

    /**
     *      依赖注入
     */
    @Test
    public void test1() {
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) act.getBean("bookService");
        bookService.save();
        System.out.println(bookService.toString());
    }
    /**
     *      Properties数据源对象的管理
     */
    @Test
    public void test2() {
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) act.getBean("dataSource");
        System.out.println(dataSource);
    }

    @Test
    public void test3() {
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        ComboPooledDataSource c3p0 = (ComboPooledDataSource) act.getBean("c3p0");
        System.out.println(c3p0);
    }

    @Test
    public void test4() {
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) act.getBean("bookDao1");
        bookDao.aaa();
    }

    @Test
    public void test5() {
        //加载类路径下的配置文件
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) act.getBean("bookDao1");
        BookDao bookDao1 = act.getBean("bookDao1", BookDao.class);
        BookService bookSer2 = act.getBean(BookService.class);
        bookDao.aaa();
        bookDao1.aaa();
        bookSer2.save();
    }
}
